/*
 *
 * Copyright (C) 2012 Walter Lütgenau
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 */
package offset.nodes.server.servlet.book.html;

import offset.nodes.server.servlet.book.epub.*;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashSet;
import java.util.Locale;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import offset.nodes.server.servlet.book.AbstractBook;
import offset.nodes.server.servlet.book.AttributesFilter;
import offset.nodes.server.servlet.book.Book;
import offset.nodes.server.servlet.book.BookInfo;
import offset.nodes.server.servlet.book.NameBuilder;

/**
 *
 * @author Walter L�tgenau
 */
public class HtmlBook extends AbstractBook implements Book {

    File file;
    ZipOutputStream zip;
    ZipEntries zipEntries = new ZipEntries();
    public static final String RESOURCE_PATH = "resource/";

    Locale locale = null;
    BookInfo info = null;
    
    NameBuilder nameBuilder = new EpubNameBuilder();
    AttributesFilter attributesFilter = new NoOpAttributesFilter();

    class ZipEntries {
        HashSet<String> entries = new HashSet<String>();

        public boolean add(ZipEntry entry, byte[] content) throws IOException {
            boolean add = true;
            if (!add || entries.contains(entry.getName()))
                return false;

            zip.putNextEntry(entry);
            zip.write(content);

            entries.add(entry.getName());

            return true;
        }
    }

    /**
     * Represents a epub book.
     *
     * Create a ZipOutputStream to a temporary file.
     * Create the opf and the toc.
     * 
     * @throws IOException
     */
    public HtmlBook() throws IOException {
        file = File.createTempFile("html", null);
        zip = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(file)));
        zipEntries = new ZipEntries();
    }

    @Override
    public void setInfo(BookInfo info) {
        this.info = info;
    }

    public void setLocale(Locale locale) {
        this.locale = locale;
    }

    protected void addFile(String path, String content) throws IOException {
        ZipEntry entry = new ZipEntry(path);
        zipEntries.add(entry, content.getBytes());
    }

    @Override
    public boolean addPage(String repositoryReference, String bookReference, String name, String content, int tocLevel) throws IOException {
        boolean addPage = super.addPage(repositoryReference, bookReference, name, content, tocLevel);
        if (!addPage)
            return false;
        
        ZipEntry entry = new ZipEntry(bookReference);
        if ( !zipEntries.add(entry, content.getBytes()))
            return false;

        return true;
    }

    @Override
    public void addResource(String repositoryReference, String bookReference, String contentType, byte[] content) throws IOException {
        ZipEntry entry = new ZipEntry(bookReference);
        if (!zipEntries.add(entry, content))
            return;
    }

 @Override
    public void addResource(String repositoryReference, String bookReference, String contentType, String content) throws IOException {
        addResource(repositoryReference, bookReference, contentType, content.getBytes());
    }


    @Override
    public void write(OutputStream output) throws IOException {
        try {
            zip.flush();            
            zip.close();
        } catch (Exception ex) {
            Logger.getLogger(HtmlBook.class.getName()).log(Level.SEVERE, null, ex);
            throw new IOException(ex.getMessage());
        }

        // copy file to output stream
        InputStream input = null;
        try {
            input = new BufferedInputStream(new FileInputStream(file));
            byte[] buf = new byte[4096];

            int count = 0;
            while ((count = input.read(buf)) > 0) {
                output.write(buf, 0, count);
            }
        } finally {
            input.close();
            file.delete();
        }
    }

    public NameBuilder getNameBuilder() {
        return nameBuilder;
    }

    @Override
    public boolean isScriptingEnabled() {
        return false;
    }

    @Override
    public AttributesFilter getAttributesFilter() {
        return attributesFilter;
    }
}
